package com.laolang.shop.modules.auth.interceptor;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.laolang.shop.common.core.consts.StatusCodeConst;
import com.laolang.shop.common.core.exception.BusinessException;
import com.laolang.shop.common.core.util.CommonUtil;
import com.laolang.shop.modules.auth.annotation.Auth;
import com.laolang.shop.modules.auth.config.JwtProperty;
import com.laolang.shop.modules.auth.entity.TokenUser;
import com.laolang.shop.modules.auth.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;

/**
 * @author khlbat
 * @version 1.0
 * @date 2020/11/1 20:46
 */
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperty jwtProperty;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    private static final String BEARER_PREFIX = "Bearer ";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object)
            throws Exception {
        // 如果不是映射到方法直接通过
        if (!(object instanceof HandlerMethod)) {
            return true;
        }
        // OPTIONS 方法直接通过
        if (ServletUtil.METHOD_OPTIONS.equals(request.getMethod())) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) object;

        // 如果方法上没有 Auth 注解或者 requireAuth 属性为 false ，直接通过
        Auth authdAnnotation = handlerMethod.getMethodAnnotation(Auth.class);
        if (null == authdAnnotation || !authdAnnotation.requireLogin()) {
            return true;
        }
        String tokenWithBearer = request.getHeader(jwtProperty.getHeader());
        if (!StrUtil.startWith(tokenWithBearer, BEARER_PREFIX)) {
            throw new BusinessException(StatusCodeConst.ERROR.getCode(), "token验证失败");
        }
        TokenUser authUser = jwtTokenUtil.getAuthUser(CommonUtil.getTokenWithoutBearer(tokenWithBearer));
        if (null == authUser) {
            throw new BusinessException(StatusCodeConst.ERROR.getCode(), "token验证失败");
        }
        SecurityContextHolder.getContext().setAuthentication(getAuthentication(CommonUtil.getTokenWithoutBearer(tokenWithBearer)));
        return true;
    }

    private UsernamePasswordAuthenticationToken getAuthentication(String token) {
        TokenUser tokenUser = jwtTokenUtil.getAuthUser(token);
        if (null != token) {
            return new UsernamePasswordAuthenticationToken(tokenUser, tokenUser.getPassword(),
                    new ArrayList<>());
        }
        return null;
    }
}
